package com.group4.datafactorybackend.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.group4.datafactorybackend.common.R;
import com.group4.datafactorybackend.common.enums.MyEnumClass;
import com.group4.datafactorybackend.common.enums.ResultCodeEnum;
import com.group4.datafactorybackend.entity.DO.*;
import com.group4.datafactorybackend.entity.DTO.*;
import com.group4.datafactorybackend.entity.VO.DataAssertDetailsVO;
import com.group4.datafactorybackend.mapper.*;
import com.group4.datafactorybackend.service.*;
import com.group4.datafactorybackend.util.CodeUtil;
import com.group4.datafactorybackend.util.SizeUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author aKUN
 * @date 2022/7/29
 * @description 数据资产业务逻辑层实现层
 */
@Service
public class DataAssertServiceImpl extends ServiceImpl<DataAssertMapper, DataAssertDO> implements DataAssertService {

    @Autowired
    private DataAssertMapper dataAssertMapper;

    @Autowired
    private DataAssertFieldMapper dataAssertFieldMapper;

    @Autowired
    private DataAssertFieldService dataAssertFieldService;

    @Autowired
    private DirectoryService directoryService;

    @Autowired
    private DafDcMapper dafDcMapper;

    @Autowired
    private DafDcService dafDcService;

    @Autowired
    private DaDirectoryMapper daDirectoryMapper;

    @Autowired
    private DaDirectoryService daDirectoryService;

    @Autowired
    private DataCriterionMapper dataCriterionMapper;

    @Autowired
    private DirectoryMapper directoryMapper;

    /**
     * @author 章珑赢
     * @param dataAssertParameterDTO 查询数据资产表条件实体类
     * @return R
     * @description 根据条件查询数据资产表
     **/
    @Override
    public R<?> selectDataAssertBy(DataAssertParameterDTO dataAssertParameterDTO) {
        LambdaQueryWrapper<DataAssertDO> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        List<String> directoryList = new ArrayList<>();
        List<String> daCodeList = new ArrayList<>();
        //判断code是否传入，根据目录进行查询
        if (dataAssertParameterDTO.getDirectoryCode() != null){
            //根据传入父级目录的Code查出全部子级目录
            directoryList = directoryService.getAllDirectoryCode(dataAssertParameterDTO.getDirectoryCode(),directoryList);
            //判断其是否为叶子节点,如果为叶子节点将本id传入根据条件进行查询，如果不为叶子节点，将其所有子目录传入
                directoryList.add(dataAssertParameterDTO.getDirectoryCode());
                LambdaQueryWrapper<DaDirectoryDO> doLambdaQueryWrapper = new LambdaQueryWrapper<>();
                doLambdaQueryWrapper.in(DaDirectoryDO::getDirectoryCode, directoryList);
                List<DaDirectoryDO> daDirectoryList = daDirectoryMapper.selectList(doLambdaQueryWrapper);
                for (DaDirectoryDO daDirectoryDO : daDirectoryList) {
                    daCodeList.add(daDirectoryDO.getDaCode());
            }
        }
        //根据数据资产表状态查询
        lambdaQueryWrapper.in(StringUtils.isNotBlank(dataAssertParameterDTO.getDirectoryCode()),DataAssertDO::getDaCode,daCodeList)
                .eq(StringUtils.isNotBlank(dataAssertParameterDTO.getDaStatus()),DataAssertDO::getDaStatus, dataAssertParameterDTO.getDaStatus())
                //根据中文名称进行模糊查询
                        .like(StringUtils.isNotBlank(dataAssertParameterDTO.getDaChName()),DataAssertDO::getDaChName, dataAssertParameterDTO.getDaChName())
                //根据英文名称进行模糊查询
                        .like(StringUtils.isNotBlank(dataAssertParameterDTO.getDaEnName()),DataAssertDO::getDaEnName, dataAssertParameterDTO.getDaEnName())
                .orderByAsc(DataAssertDO::getDaStatus)
                .orderByDesc(DataAssertDO::getUpdateTime);
        //分页
        Page<DataAssertDO> page = new Page<>(dataAssertParameterDTO.getPageNum(), dataAssertParameterDTO.getPageSize());
        Page<DataAssertDO> dataAssertDoPage = dataAssertMapper.selectPage(page, lambdaQueryWrapper);
        return R.Success(ResultCodeEnum.SUCCESS,dataAssertDoPage);
    }

    /**
     * @author 李泓静
     * @param daCode 数据资产编号
     * @return List
     * @description 根据编号查询数据资产表详情
     */
    @Override
    public R<?> getDataAssertField(String daCode) {
        //根据资产编号查询资产字段信息
        DataAssertDetailsVO dataAssertDetailsVO = new DataAssertDetailsVO();
        LambdaQueryWrapper<DataAssertFieldDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DataAssertFieldDO::getDaCode,daCode);
        List<DataAssertFieldDO> dataAssertFieldList = dataAssertFieldMapper.selectList(wrapper);
        //判断数据资产字段是否为空
        if( CollectionUtils.isEmpty(dataAssertFieldList)){
            return R.Failed(ResultCodeEnum.INTERFACE_BASE_NOT_FOUND);
        }
        //新建一个DataAssertCodeDTO实体和集合
        List<DataAssertCodeDTO> dataAssertCodeList = new ArrayList<>();
        //新建一个数据标准目录wrapper
        LambdaQueryWrapper<DataCriterionDO> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        for (DataAssertFieldDO dataAssertFieldDO : dataAssertFieldList) {
            //根据查到的字段信息查找对应的数据标准字段
            DataAssertCodeDTO dataAssertCodeDTO = new DataAssertCodeDTO();
            //清空wrapper
            if(StringUtils.isNotBlank(dataAssertFieldDO.getDcCode())){
                lambdaQueryWrapper.clear();
                lambdaQueryWrapper.eq(DataCriterionDO::getDcCode,dataAssertFieldDO.getDcCode());
                DataCriterionDO dataCriterionDO = dataCriterionMapper.selectOne(lambdaQueryWrapper);
                if(! ObjectUtils.isEmpty(dataCriterionDO)){
                    //将查询结果复制给dataAssertCodeDTO
                    BeanUtils.copyProperties(dataCriterionDO,dataAssertCodeDTO);
                }
            }
            BeanUtils.copyProperties(dataAssertFieldDO,dataAssertCodeDTO);
            //往list添加dataAssertCodeDTO对象
            dataAssertCodeList.add(dataAssertCodeDTO);
        }
        //把查询结果set到dataAssertDetailsVO对象
        dataAssertDetailsVO.setDataAssertCodeDTOList(dataAssertCodeList);

        //查询所属目录r
        LambdaQueryWrapper<DaDirectoryDO> daDireWrapper = new LambdaQueryWrapper<>();
        //根据资产code查询数据资产-目录关联表
        daDireWrapper.eq(DaDirectoryDO::getDaCode, daCode);
        List<DaDirectoryDO> daDirectoryList = daDirectoryMapper.selectList(daDireWrapper);
        //判断结果是否为空
        if(! CollectionUtils.isEmpty(daDirectoryList)){
            // 目录名称集合
            List<String> directoryNameList = new ArrayList<>();
            // 目录表wrapper
            LambdaQueryWrapper<DirectoryDO> directoryWrapper = new LambdaQueryWrapper<>();
            for (DaDirectoryDO daDirectoryDO : daDirectoryList) {
                directoryWrapper.clear();
                //如果目录code为空时结束本层循环
                if(StringUtils.isNotBlank(daDirectoryDO.getDirectoryCode())){
                    continue;
                }
                //根据目录code查询目录信息
                directoryWrapper.eq(DirectoryDO::getDirectoryCode, daDirectoryDO.getDirectoryCode());
                DirectoryDO directory = directoryMapper.selectOne(directoryWrapper);
                List<String> nameList = new ArrayList<>();
                if (!directory.getParentCode().equals(directory.getMenuCode().toString())){
                    //查询父级
                    nameList = directoryService.pathParentDirectoryNameIsRepeat(directory.getParentCode(), nameList);
                    //倒序
                    Collections.reverse(nameList);
                    StringBuilder directoryName = new StringBuilder();
                    for (String name : nameList) {
                        directoryName.append(name).append("/");
                    }
                    directoryName.append(directory.getDirectoryName());
                    directoryNameList.add(directoryName.toString());
                }else{
                    directoryNameList.add(directory.getDirectoryName());
                }
            }
            dataAssertDetailsVO.setDirectoryNameList(directoryNameList);
        }
        //把查询结果set到dataAssertDetailsVO对象
        dataAssertDetailsVO.setDataAssertCodeDTOList(dataAssertCodeList);
        return R.Success(ResultCodeEnum.SUCCESS,dataAssertDetailsVO);
    }

    /**
     * @author OKer
     * @param createOrUpdateDataAssertDTO 新增、修改数据资产表接收参数实体类
     * @return R
     * @description 新增、编辑数据资产
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<?> createOrUpdateDataAssert(CreateOrUpdateDataAssertDTO createOrUpdateDataAssertDTO) {
        // 调用校验
        R<?> result = this.verifyDataAssertData(createOrUpdateDataAssertDTO);
        if (result.failed()) {
            return result;
        }
        try {
            // 如果是新增还是编辑操作，添加数据资产编号
            if (StringUtils.isBlank(createOrUpdateDataAssertDTO.getDaCode())) {
                createOrUpdateDataAssertDTO.setDaCode(CodeUtil.getCode());
            }else {
                // 查询改数据资产表下的所有数据资产字段
                LambdaQueryWrapper<DataAssertFieldDO> queryDafWrapper = new LambdaQueryWrapper<>();
                queryDafWrapper.eq(DataAssertFieldDO::getDaCode, createOrUpdateDataAssertDTO.getDaCode());
                List<DataAssertFieldDO> dataAssertFieldList = dataAssertFieldMapper.selectList(queryDafWrapper);
                if (ObjectUtils.isEmpty(dataAssertFieldList)) {
                    return R.Failed(ResultCodeEnum.OPERATION_FAILED, "编辑失败，错误的数据资产编号");
                }
                // 清空数据资产字段
                dataAssertFieldMapper.delete(queryDafWrapper);
                // 清空数据资产字段标准映射
                LambdaQueryWrapper<DafDcDO> deleteDafDcWrapper = new LambdaQueryWrapper<>();
                for (DataAssertFieldDO dataAssertField : dataAssertFieldList) {
                    if (StringUtils.isBlank(dataAssertField.getDcCode())) {
                        deleteDafDcWrapper.clear();
                        dafDcMapper.delete(deleteDafDcWrapper);
                    }
                }
                // 根据数据资产编号清空所属目录
                LambdaQueryWrapper<DaDirectoryDO> deleteDaDirectoryWrapper = new LambdaQueryWrapper<>();
                deleteDaDirectoryWrapper.eq(DaDirectoryDO::getDaCode, createOrUpdateDataAssertDTO.getDaCode());
                daDirectoryMapper.delete(deleteDaDirectoryWrapper);
            }
            // 存入字段与标准映射
            List<DataAssertFieldDO> dataAssertFieldDOList = new ArrayList<>();
            List<DafDcDO> dafDcDOList = new ArrayList<>();
            for (CreateOrUpdateDataAssertFieldDTO addDataAssertFieldDTO : createOrUpdateDataAssertDTO.getDaFieldDTO()) {
                // 生成数据资产字段编号
                addDataAssertFieldDTO.setDafCode(CodeUtil.getCode());

                // 装载数据资产字段
                DataAssertFieldDO dataAssertFieldDO = new DataAssertFieldDO();
                BeanUtils.copyProperties(addDataAssertFieldDTO,dataAssertFieldDO);
                dataAssertFieldDO.setDaCode(createOrUpdateDataAssertDTO.getDaCode());
                dataAssertFieldDOList.add(dataAssertFieldDO);

                // 装载字段与标准映射的关系,如果码表编号为空表示未引用码表，则无需装载
                if (StringUtils.isNotBlank(addDataAssertFieldDTO.getDcCode())) {
                    // 判断码表编号是否是数据库中存在的
                    DafDcDO dafDcDO = new DafDcDO();
                    dafDcDO.setDafCode(addDataAssertFieldDTO.getDafCode());
                    dafDcDO.setDcCode(addDataAssertFieldDTO.getDcCode());
                    dafDcDOList.add(dafDcDO);
                }
            }
            this.dataAssertFieldService.saveBatch(dataAssertFieldDOList, dataAssertFieldDOList.size());
            this.dafDcService.saveBatch(dafDcDOList, dafDcDOList.size());

            // 存入所属目录
            List<DaDirectoryDO> daDirectoryList = new ArrayList<>();
            for (String directoryCode : createOrUpdateDataAssertDTO.getDirectoryNameList()) {
                //装载数据
                DaDirectoryDO daDirectory = new DaDirectoryDO();
                daDirectory.setDirectoryCode(directoryCode);
                daDirectory.setDaCode(createOrUpdateDataAssertDTO.getDaCode());
                daDirectoryList.add(daDirectory);
            }
            this.daDirectoryService.saveBatch(daDirectoryList, daDirectoryList.size());

            // 存入基本信息进入数据库
            DataAssertDO dataAssert = new DataAssertDO();
            BeanUtils.copyProperties(createOrUpdateDataAssertDTO, dataAssert);
            this.dataAssertMapper.insert(dataAssert);
        } catch (Exception e) {
            e.printStackTrace();
            return R.Failed(ResultCodeEnum.OPERATION_FAILED);
        }
        return R.Success(ResultCodeEnum.OPERATION_SUCCESS);
    }

    /**
     * @author 卑微小峰
     * @param daCode 数据资产编号
     * @return R
     * @description
     */
    @Override
    public R<?> deleteDataAssert(String daCode) {
        /*
        * 1、删除与数据标准引用
        * 2、删除与目录的关系
        * 3、删除数据资产表
        */
        // 获取此数据资产表下的所有数据资产字段
        LambdaQueryWrapper<DataAssertFieldDO> queryDataAssertFieldWrapper = new LambdaQueryWrapper<>();
        queryDataAssertFieldWrapper.eq(DataAssertFieldDO::getDaCode, daCode)
                .isNotNull(DataAssertFieldDO::getDafCode);
        List<DataAssertFieldDO> dataAssertFieldList = dataAssertFieldMapper.selectList(queryDataAssertFieldWrapper);

        try {
            LambdaQueryWrapper<DafDcDO> deleteQuoteWrapper = new LambdaQueryWrapper<>();
            for (DataAssertFieldDO dataAssertField : dataAssertFieldList) {
                deleteQuoteWrapper.clear();
                // 删除与数据标准引用
                deleteQuoteWrapper.eq(DafDcDO::getDafCode, dataAssertField.getDafCode());
                dafDcMapper.delete(deleteQuoteWrapper);
            }
            // 删除与目录的关系
            LambdaQueryWrapper<DaDirectoryDO> deleteRelationWrapper = new LambdaQueryWrapper<>();
            deleteRelationWrapper.eq(DaDirectoryDO::getDaCode, daCode);
            daDirectoryMapper.delete(deleteRelationWrapper);

            // 删除数据资产表
            LambdaQueryWrapper<DataAssertDO> deleteDataAssertWrapper = new LambdaQueryWrapper<>();
            deleteDataAssertWrapper.eq(DataAssertDO::getDaCode, daCode);
            dataAssertMapper.delete(deleteDataAssertWrapper);
        } catch (Exception e) {
            e.printStackTrace();
            return R.Failed(ResultCodeEnum.OPERATION_FAILED);
        }
        return R.Success(ResultCodeEnum.OPERATION_SUCCESS);
    }

    /**
     * @author 卑微小峰
     * @param batchReleaseOrOutageDTO （批量）发布/停用接收参数实体类
     * @return R
     * @description （批量）发布/停用数据资产表
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<?> releaseOrOutage(BatchReleaseOrOutageDTO batchReleaseOrOutageDTO) {
        Integer status = batchReleaseOrOutageDTO.getStatus();
        List<String> dataAssertCodeList = batchReleaseOrOutageDTO.getCodeList();

        // （批量）停用时判断批量操作中是否存在未发布的数据资产表
        if (status.equals(MyEnumClass.StatusEnum.HAVE_DISABLE.getCode())) {
            LambdaQueryWrapper<DataAssertDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(DataAssertDO::getDaStatus, MyEnumClass.StatusEnum.NOT_RELEASE.getCode())
                    .in(DataAssertDO::getDaCode, dataAssertCodeList);
            int result = dataAssertMapper.selectCount(lambdaQueryWrapper);
            if (result > 0) {
                return R.Failed(ResultCodeEnum.EXIST_NOT_RELEASE.getCode(), "存在未发布的数据资产表");
            }
        }
        // （批量）发布时判断批量操作中是否存在已发布的数据资产表
        if (status.equals(MyEnumClass.StatusEnum.HAVE_RELEASE.getCode())) {
            LambdaQueryWrapper<DataAssertDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(DataAssertDO::getDaStatus, MyEnumClass.StatusEnum.HAVE_RELEASE.getCode())
                    .in(DataAssertDO::getDaCode, dataAssertCodeList);
            int result = dataAssertMapper.selectCount(lambdaQueryWrapper);
            if (result > 0) {
                return R.Failed(ResultCodeEnum.EXIST_HAVE_RELEASE.getCode(), "存在已发布的数据资产表");
            }
        }

        try {
            // 开启/停止数据资产字段对码表的引用
            for (String dataAssertCode : dataAssertCodeList) {
                // 查询此数据资产编号下的所有含有数据标准目录的数据资产字段编号
                List<String> dataAssertFieldCodeList = dataAssertMapper.getHasDataCriterionQuoteDataAssertCodeList(dataAssertCode);

                // 存在含有码值定义的接口参数配置，先开启（关闭）引用，再修改发布状态
                if (dataAssertFieldCodeList.size() > 0) {
                    LambdaUpdateWrapper<DafDcDO> updateQuoteDataCriterionStatusWrapper = new LambdaUpdateWrapper<>();
                    if (MyEnumClass.StatusEnum.HAVE_RELEASE.getCode().equals(status)) {
                        updateQuoteDataCriterionStatusWrapper.in(DafDcDO::getDafCode, dataAssertFieldCodeList)
                                .set(DafDcDO::getIsDisable, MyEnumClass.QuoteStatusEnum.OPEN_QUOTE.getCode());
                        dafDcMapper.update(null, updateQuoteDataCriterionStatusWrapper);
                    }else if (status.equals(MyEnumClass.StatusEnum.HAVE_DISABLE.getCode())) {
                        updateQuoteDataCriterionStatusWrapper.in(DafDcDO::getDafCode, dataAssertFieldCodeList)
                                .set(DafDcDO::getIsDisable, MyEnumClass.QuoteStatusEnum.CLOSE_QUOTE.getCode());
                        dafDcMapper.update(null, updateQuoteDataCriterionStatusWrapper);
                    }else  {
                        return R.Failed("错误的状态值");
                    }
                }
            }

            // （批量）发布/停用数据资产字段
            LambdaUpdateWrapper<DataAssertDO> releaseOrOutageWrapper = new LambdaUpdateWrapper<>();
            releaseOrOutageWrapper.in(DataAssertDO::getDaCode, dataAssertCodeList)
                    .set(DataAssertDO::getDaStatus, status);
            int result = dataAssertMapper.update(null,releaseOrOutageWrapper);
            if (result > 0) {
                return R.Success(ResultCodeEnum.OPERATION_SUCCESS,result);
            }
            return R.Failed(ResultCodeEnum.OPERATION_FAILED);
        } catch (Exception e) {
            return R.Failed(ResultCodeEnum.OPERATION_FAILED);
        }
    }

    /**
     * @author 卑微小峰
     * @param createOrUpdateDataAssertDTO 新增、修改数据资产表接收参数实体类
     * @return R
     * @description 新增/编辑数据资产表数据校验
     */
    private R<?> verifyDataAssertData(@RequestBody @Validated CreateOrUpdateDataAssertDTO createOrUpdateDataAssertDTO) {
        LambdaQueryWrapper<DirectoryDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(DirectoryDO::getDirectoryCode, createOrUpdateDataAssertDTO.getDirectoryNameList());
        List<DirectoryDO> directoryList = directoryMapper.selectList(queryWrapper);
        if (createOrUpdateDataAssertDTO.getDirectoryNameList().size() != directoryList.size()) {
            return R.Failed("目录分类不存在");
        }
        LambdaQueryWrapper<DataAssertDO> queryDataAssertWrapper = new LambdaQueryWrapper<>();
        // 验证数据资产中文名称、英文名称是否重复
        queryDataAssertWrapper.eq(DataAssertDO::getDaChName, createOrUpdateDataAssertDTO.getDaChName())
                .or()
                .eq(DataAssertDO::getDaEnName, createOrUpdateDataAssertDTO.getDaEnName());
        if (!StringUtils.isBlank(createOrUpdateDataAssertDTO.getDaCode())) {
            // 编辑校验
            queryDataAssertWrapper.ne(DataAssertDO::getDaCode, createOrUpdateDataAssertDTO.getDaCode());
        }
        // 数据资产重名校验
        int nameCount = dataAssertMapper.selectCount(queryDataAssertWrapper);
        if (nameCount > 0) {
            return R.Failed(ResultCodeEnum.DATA_EXIST.getCode(), "中文名称或英文名称已存在");
        }

        //判断字段中中文名，英文名是否存在重复
        List<String> dafChNames = new ArrayList<>();
        List<String> dafEnNames = new ArrayList<>();
        for (CreateOrUpdateDataAssertFieldDTO addDataAssertFieldDTO : createOrUpdateDataAssertDTO.getDaFieldDTO()) {
            dafChNames.add(addDataAssertFieldDTO.getDafChName());
            dafEnNames.add(addDataAssertFieldDTO.getDafEnName());
        }
        // 判断中文名称是否重复
        boolean bool = SizeUtils.siblingRepetition(dafChNames);
        if (!bool){
            return R.Failed(ResultCodeEnum. CN_NAME_REPEAT,false);
        }
        // 判断英文名称是否重复
        bool = SizeUtils.siblingRepetition(dafEnNames);
        if (!bool){
            return R.Failed(ResultCodeEnum.EN_NAME_REPEAT,false);
        }
        return R.Success(ResultCodeEnum.SUCCESS, true);
    }
}
